﻿using System;
using System.Windows;
using System.Windows.Media;

namespace LooseChart
{
    public class LinearAxis : IAxis
    {
        /// <summary>
        /// 10的次方数
        /// </summary>
        public int Power
        {
            get { return (int)GetValue(PowerProperty); }
            private set { SetValue(PowerProperty, value); }
        }
        public static readonly DependencyProperty PowerProperty = DependencyProperty.Register("Power", typeof(int), typeof(LinearAxis), new PropertyMetadata(0));

        public LinearAxis() : base() { }

        /// <summary>
        /// 实际值转坐标值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public override double ValueToAxisValue(double value, ValueAxisConvertParamBase param)
        {
            return value;
        }
        /// <summary>
        /// 坐标值转实际值
        /// </summary>
        /// <param name="axisvalue"></param>
        /// <returns></returns>
        public override double AxisValueToValue(double axisvalue, ValueAxisConvertParamBase param)
        {
            return axisvalue;
        }

        public override void Draw()
        {
            if (!this.IsLoaded) return;
            var valuelocationparam = GetConvertParam();
            var powermax = Math.Floor(Max == 0 ? 0 : Math.Log10(Math.Abs(Max)));
            var powermin = Math.Floor(Min == 0 ? powermax < 0 ? powermax * 2 : powermax / 2 : Math.Log10(Math.Abs(Min)));
            Power = Convert.ToInt32((powermax + powermin) / 2);
            var powervalue = Convert.ToDouble(Math.Pow(10, Power));
            var range = Max - Min;
            int count;
            if (range < 1)
            {
                var temp = range;
                int i = 0;
                while (temp % 1 > 0d)
                {
                    i++;
                    temp *= 10;
                }
                count = Convert.ToInt32(valuelocationparam.Length / (Math.Max(i, 3) * FontSize));
            }
            else
            {
                var tempmax = Max.ToString();
                var tempmin = Min.ToString();
                int i = 0;
                while (tempmax.Length > i && tempmin.Length > i && tempmax[i] == tempmin[i]) i++;
                count = Convert.ToInt32(valuelocationparam.Length / (Math.Max(i, 3) * FontSize));
            }

            var subrange = GetSubRange(range, count);
            var start = Min % subrange != 0d ? (Min - Min % subrange) : Min;
            var minsubrange = subrange / 10;
            using (var dc = DV.RenderOpen())
            {
                dc.DrawRectangle(Background, null, new Rect(0, 0, this.ActualWidth, this.ActualHeight));
                var ft = new FormattedText(Power.ToString(), System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, DefaultTypeface, PowerFontSize, Foreground, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                var fst = new FormattedText("x10", System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, DefaultTypeface, FontSize, Foreground, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                var ftg = ft.BuildGeometry(PointZero);
                var fstg = fst.BuildGeometry(PointZero);
                if (valuelocationparam.AxisType == AxisType.X)
                {
                    dc.DrawLine(LinePen, new Point(0, 0), new Point(this.ActualWidth, 0));
                    ftg.Transform = new MatrixTransform(1, 0, 0, 1, this.ActualWidth - ft.Width - 5, this.ActualHeight - fst.Height);
                    fstg.Transform = new MatrixTransform(1, 0, 0, 1, this.ActualWidth - ft.Width - fst.Width - 5, this.ActualHeight - fst.Height);
                }
                else if (valuelocationparam.AxisType == AxisType.Y)
                {
                    dc.DrawLine(LinePen, new Point(this.ActualWidth, 0), new Point(this.ActualWidth, this.ActualHeight));
                    ftg.Transform = new MatrixTransform(0, -1, 1, 0, 0, ft.Width + 5);
                    fstg.Transform = new MatrixTransform(0, -1, 1, 0, 0, ft.Width + fst.Width + 5);
                }
                else
                {
                    dc.DrawLine(LinePen, new Point(0, 0), new Point(0, this.ActualHeight));
                    ftg.Transform = new MatrixTransform(0, 1, -1, 0, this.ActualWidth, fst.Width + 5);
                    fstg.Transform = new MatrixTransform(0, 1, -1, 0, this.ActualWidth, 5);
                }
                dc.DrawGeometry(Foreground, StringPen, ftg);
                dc.DrawGeometry(Foreground, StringPen, fstg);
                for (int i = 0; i < range / subrange; i++)
                {
                    var value = Convert.ToDouble(start) + Convert.ToDouble(i * Convert.ToDecimal(subrange));
                    var valuestr = (value / powervalue).ToString();
                    var valuelocation = GetValueLocation(value);
                    var vft = new FormattedText(valuestr, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, DefaultTypeface, FontSize, Foreground, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                    var vftg = vft.BuildGeometry(PointZero);
                    if (valuelocation >= 0 && valuelocation <= valuelocationparam.Length)
                    {
                        if (valuelocationparam.AxisType == AxisType.X)
                        {
                            dc.DrawLine(LinePen, new Point(valuelocation, 0), new Point(valuelocation, 5));
                            vftg.Transform = new MatrixTransform(1, 0, 0, 1, valuelocation - vft.Width / 2, 5);
                        }
                        else if (valuelocationparam.AxisType == AxisType.Y)
                        {
                            dc.DrawLine(LinePen, new Point(this.ActualWidth, valuelocation), new Point(this.ActualWidth - 5, valuelocation));
                            vftg.Transform = new MatrixTransform(0, -1, 1, 0, this.ActualWidth - 10 - FontSize, valuelocation + vft.Width / 2);
                        }
                        else
                        {
                            dc.DrawLine(LinePen, new Point(0, valuelocation), new Point(5, valuelocation));
                            vftg.Transform = new MatrixTransform(0, 1, -1, 0, 10 + FontSize, valuelocation - vft.Width / 2);
                        }
                        dc.DrawGeometry(Foreground, StringPen, vftg);
                    }
                    for (int j = 1; j < 10; j++)
                    {
                        var subv = value + j * minsubrange;
                        if (subv < Min || subv > Max) continue;
                        var subvaluelocation = GetValueLocation(subv);
                        if (valuelocationparam.AxisType == AxisType.X) dc.DrawLine(LinePen, new Point(subvaluelocation, 0), new Point(subvaluelocation, 3));
                        else if (valuelocationparam.AxisType == AxisType.Y) dc.DrawLine(LinePen, new Point(this.ActualWidth, subvaluelocation), new Point(this.ActualWidth - 3, subvaluelocation));
                        else dc.DrawLine(LinePen, new Point(0, subvaluelocation), new Point(3, subvaluelocation));
                    }
                    if (i == 0)
                    {
                        for (int j = 1; j < 10; j++)
                        {
                            var subv = value - j * minsubrange;
                            if (subv < Min || subv > Max) continue;
                            var subvaluelocation = GetValueLocation(subv);
                            if (valuelocationparam.AxisType == AxisType.X) dc.DrawLine(LinePen, new Point(subvaluelocation, 0), new Point(subvaluelocation, 3));
                            else if (valuelocationparam.AxisType == AxisType.Y) dc.DrawLine(LinePen, new Point(this.ActualWidth, subvaluelocation), new Point(this.ActualWidth - 3, subvaluelocation));
                            else dc.DrawLine(LinePen, new Point(0, subvaluelocation), new Point(3, subvaluelocation));
                        }
                    }
                }
            }
        }
    }
}
